home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2005 June
/
ccd0605.iso
/
Software
/
Freeware
/
Programare
/
highlight
/
highlight-W32GUI-2.2-10b-Setup.exe
/
{app}
/
src
/
ASFormatter.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2004-06-29
|
55KB
|
1,634 lines
/*
* Copyright (c) 1998,1999,2000,2001,2002 Tal Davidson. All rights reserved.
*
* ASFormatter.cpp
* by Tal Davidson (davidsont@bigfoot.com)
* This file is a part of "Artistic Style" - an indentater and reformatter
* of C, C++, C# and Java source files.
*
* The "Artistic Style" project, including all files needed to compile it,
* is free software; you can redistribute it and/or use it and/or modify it
* under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU General Public
* License along with this program.
*
*
* Patches:
* 26 November 1998 - Richard Bullington -
* A correction of line-breaking in headers following '}',
* was created using a variation of a patch by Richard Bullington.
* 08 May 2004
* applied ASFormatter450670.patch.bz2, ASFormatter.cpp.patch.bz2,
* patch1_ssvb_patch.tar.gz
*/
#include "compiler_defines.h"
#include "ASFormatter.h"
#include <string>
#include <cctype>
#include <vector>
#include <algorithm>
#include <iostream>
#define INIT_CONTAINER(container, value) {if ( (container) != NULL ) delete (container); (container) = (value); }
#define DELETE_CONTAINER(container) {if ( (container) != NULL ) delete (container) ; }
#define IS_A(a,b) ( ((a) & (b)) == (b))
#ifdef USES_NAMESPACE
using namespace std;
namespace astyle
{
#endif
bool ASFormatter::calledInitStatic = false;
vector<const string*> ASFormatter::headers;
vector<const string*> ASFormatter::nonParenHeaders;
vector<const string*> ASFormatter::preprocessorHeaders;
vector<const string*> ASFormatter::preDefinitionHeaders;
vector<const string*> ASFormatter::preCommandHeaders;
vector<const string*> ASFormatter::operators;
vector<const string*> ASFormatter::assignmentOperators;
/**
* Constructor of ASFormatter
*/
ASFormatter::ASFormatter()
{
staticInit();
preBracketHeaderStack = NULL;
bracketTypeStack = NULL;
parenStack = NULL;
sourceIterator = NULL;
bracketFormatMode = NONE_MODE;
shouldPadOperators = false;
shouldPadParenthesies = false;
shouldBreakOneLineBlocks = true;
shouldBreakOneLineStatements = true;
shouldConvertTabs = false;
shouldBreakBlocks = false;
shouldBreakClosingHeaderBlocks = false;
shouldBreakClosingHeaderBrackets = false;
shouldBreakElseIfs = false;
}
/**
* Destructor of ASFormatter
*/
ASFormatter::~ASFormatter()
{
DELETE_CONTAINER( preBracketHeaderStack );
}
/**
* initialization of static data of ASFormatter.
*/
void ASFormatter::staticInit()
{
if (calledInitStatic)
return;
calledInitStatic = true;
headers.push_back(&AS_IF);
headers.push_back(&AS_ELSE);
headers.push_back(&AS_DO);
headers.push_back(&AS_WHILE);
headers.push_back(&AS_FOR);
headers.push_back(&AS_SYNCHRONIZED);
headers.push_back(&AS_TRY);
headers.push_back(&AS_CATCH);
headers.push_back(&AS_FINALLY);
headers.push_back(&AS_SWITCH);
headers.push_back(&AS_TEMPLATE);
headers.push_back(&AS_FOREACH);
headers.push_back(&AS_LOCK);
headers.push_back(&AS_UNSAFE);
headers.push_back(&AS_FIXED);
headers.push_back(&AS_GET);
headers.push_back(&AS_SET);
headers.push_back(&AS_ADD);
headers.push_back(&AS_REMOVE);
nonParenHeaders.push_back(&AS_ELSE);
nonParenHeaders.push_back(&AS_DO);
nonParenHeaders.push_back(&AS_TRY);
nonParenHeaders.push_back(&AS_FINALLY);
nonParenHeaders.push_back(&AS_UNSAFE);
nonParenHeaders.push_back(&AS_GET);
nonParenHeaders.push_back(&AS_SET);
nonParenHeaders.push_back(&AS_ADD);
nonParenHeaders.push_back(&AS_REMOVE);
// nonParenHeaders.push_back(&AS_TEMPLATE);
preDefinitionHeaders.push_back(&AS_CLASS);
preDefinitionHeaders.push_back(&AS_INTERFACE);
preDefinitionHeaders.push_back(&AS_NAMESPACE);
preDefinitionHeaders.push_back(&AS_STRUCT);
preCommandHeaders.push_back(&AS_EXTERN);
preCommandHeaders.push_back(&AS_THROWS);
preCommandHeaders.push_back(&AS_CONST);
preprocessorHeaders.push_back(&AS_BAR_DEFINE);
//// DEVEL: removed the folowing lines
////preprocessorHeaders.push_back(&AS_BAR_INCLUDE);
////preprocessorHeaders.push_back(&AS_BAR_IF); // #if or #ifdef
////preprocessorHeaders.push_back(&AS_BAR_EL); // #else or #elif
////preprocessorHeaders.push_back(&AS_BAR_ENDIF);
operators.push_back(&AS_PLUS_ASSIGN);
operators.push_back(&AS_MINUS_ASSIGN);
operators.push_back(&AS_MULT_ASSIGN);
operators.push_back(&AS_DIV_ASSIGN);
operators.push_back(&AS_MOD_ASSIGN);
operators.push_back(&AS_OR_ASSIGN);
operators.push_back(&AS_AND_ASSIGN);
operators.push_back(&AS_XOR_ASSIGN);
operators.push_back(&AS_EQUAL);
operators.push_back(&AS_PLUS_PLUS);
operators.push_back(&AS_MINUS_MINUS);
operators.push_back(&AS_NOT_EQUAL);
operators.push_back(&AS_GR_EQUAL);
operators.push_back(&AS_GR_GR_GR_ASSIGN);
operators.push_back(&AS_GR_GR_ASSIGN);
operators.push_back(&AS_GR_GR_GR);
operators.push_back(&AS_GR_GR);
operators.push_back(&AS_LS_EQUAL);
operators.push_back(&AS_LS_LS_LS_ASSIGN);
operators.push_back(&AS_LS_LS_ASSIGN);
operators.push_back(&AS_LS_LS_LS);
operators.push_back(&AS_LS_LS);
operators.push_back(&AS_ARROW);
operators.push_back(&AS_AND);
operators.push_back(&AS_OR);
operators.push_back(&AS_COLON_COLON);
//// BUGFIX: removed the folowing lines
//// operators.push_back(&AS_PAREN_PAREN);
//// operators.push_back(&AS_BLPAREN_BLPAREN);
operators.push_back(&AS_PLUS);
operators.push_back(&AS_MINUS);
operators.push_back(&AS_MULT);
operators.push_back(&AS_DIV);
operators.push_back(&AS_MOD);
operators.push_back(&AS_QUESTION);
operators.push_back(&AS_COLON);
operators.push_back(&AS_ASSIGN);
operators.push_back(&AS_LS);
operators.push_back(&AS_GR);
operators.push_back(&AS_NOT);
operators.push_back(&AS_BIT_OR);
operators.push_back(&AS_BIT_AND);
operators.push_back(&AS_BIT_NOT);
operators.push_back(&AS_BIT_XOR);
operators.push_back(&AS_OPERATOR);
operators.push_back(&AS_COMMA);
//BEGIN Content Patch patch1_ssvb_patch.tar.gz
operators.push_back(&AS_SEMICOLON);
//END Content Patch patch1_ssvb_patch.tar.gz
operators.push_back(&AS_RETURN);
assignmentOperators.push_back(&AS_PLUS_ASSIGN);
assignmentOperators.push_back(&AS_MINUS_ASSIGN);
assignmentOperators.push_back(&AS_MULT_ASSIGN);
assignmentOperators.push_back(&AS_DIV_ASSIGN);
assignmentOperators.push_back(&AS_MOD_ASSIGN);
assignmentOperators.push_back(&AS_XOR_ASSIGN);
assignmentOperators.push_back(&AS_OR_ASSIGN);
assignmentOperators.push_back(&AS_AND_ASSIGN);
assignmentOperators.push_back(&AS_GR_GR_GR_ASSIGN);
assignmentOperators.push_back(&AS_LS_LS_LS_ASSIGN);
assignmentOperators.push_back(&AS_ASSIGN);
}
/**
* initialize the ASFormatter.
*
* init() should be called every time a ASFormatter object is to start
* formatting a NEW source file.
* init() recieves a pointer to a DYNAMICALLY CREATED ASSourceIterator object
* that will be used to iterate through the source code. This object will be
* deleted during the ASFormatter's destruction, and thus should not be
* deleted elsewhere.
*
* @param iter a pointer to the DYNAMICALLY CREATED ASSourceIterator object.
*/
void ASFormatter::init(ASSourceIterator *si)
{
ASBeautifier::init(si);
sourceIterator = si;
INIT_CONTAINER( preBracketHeaderStack, new vector<const string*> );
INIT_CONTAINER( bracketTypeStack, new vector<BracketType> );
bracketTypeStack->push_back(DEFINITION_TYPE);
INIT_CONTAINER( parenStack, new vector<int> );
parenStack->push_back(0);
currentHeader = NULL;
currentLine = string("");
formattedLine = "";
currentChar = ' ';
previousCommandChar = ' ';
previousNonWSChar = ' ';
quoteChar = '"';
charNum = 0;
previousOperator = NULL;
isVirgin = true;
isInLineComment = false;
isInComment = false;
isInPreprocessor = false;
doesLineStartComment = false;
isInQuote = false;
isSpecialChar = false;
isNonParenHeader = true;
foundPreDefinitionHeader = false;
foundPreCommandHeader = false;
foundQuestionMark = false;
isInLineBreak = false;
endOfCodeReached = false;
isLineReady = false;
isPreviousBracketBlockRelated = true;
isInPotentialCalculation = false;
//foundOneLineBlock = false;
shouldReparseCurrentChar = false;
passedSemicolon = false;
passedColon = false;
isInTemplate = false;
shouldBreakLineAfterComments = false;
isImmediatelyPostComment = false;
isImmediatelyPostLineComment = false;
isImmediatelyPostEmptyBlock = false;
isPrependPostBlockEmptyLineRequested = false;
isAppendPostBlockEmptyLineRequested = false;
prependEmptyLine = false;
foundClosingHeader = false;
previousReadyFormattedLineLength = 0;
isImmediatelyPostHeader = false;
isInHeader = false;
}
/**
* get the next formatted line.
*
* @return formatted line.
*/
string ASFormatter::nextLine()
{
const string *newHeader;
bool isCharImmediatelyPostComment = false;
bool isPreviousCharPostComment = false;
bool isCharImmediatelyPostLineComment = false;
bool isInVirginLine = isVirgin;
bool isCharImmediatelyPostOpenBlock = false;
bool isCharImmediatelyPostCloseBlock = false;
bool isCharImmediatelyPostTemplate = false;
bool isCharImmediatelyPostHeader = false;
if (!isFormattingEnabled())
return ASBeautifier::nextLine();
while (!isLineReady)
{
if (shouldReparseCurrentChar)
shouldReparseCurrentChar = false;
else if (!getNextChar())
{
breakLine();
return beautify(readyFormattedLine);
}
else // stuff to do when reading a new character...
{
// make sure that a virgin '{' at the begining ofthe file will be treated as a block...
if (isInVirginLine && currentChar == '{')
previousCommandChar = '{';
isPreviousCharPostComment = isCharImmediatelyPostComment;
isCharImmediatelyPostComment = false;
isCharImmediatelyPostTemplate = false;
isCharImmediatelyPostHeader = false;
}
if (isInLineComment)
{
appendCurrentChar();
// explicitely break a line when a line comment's end is found.
if (/*bracketFormatMode == ATTACH_MODE &&*/ charNum+1 == currentLine.length())
{
isInLineBreak = true;
isInLineComment = false;
isImmediatelyPostLineComment = true;
currentChar = 0; //make sure it is a neutral char.
}
continue;
}
else if (isInComment)
{
if (isSequenceReached(AS_CLOSE_COMMENT))
{
isInComment = false;
isImmediatelyPostComment = true;
appendSequence(AS_CLOSE_COMMENT);
goForward(1);
}
else
appendCurrentChar();
continue;
}
// not in line comment or comment
else if (isInQuote)
{
if (isSpecialChar)
{
isSpecialChar = false;
appendCurrentChar();
}
else if (currentChar == '\\')
{
isSpecialChar = true;
appendCurrentChar();
}
else if (quoteChar == currentChar)
{
isInQuote = false;
appendCurrentChar();
}
else
{
appendCurrentChar();
}
continue;
}
// handle white space - needed to simplify the rest.
if (isWhiteSpace(currentChar) || isInPreprocessor)
{
////// DEVEL: if (isLegalNameChar(previousChar) && isLegalNameChar(peekNextChar()))
appendCurrentChar();
continue;
}
/* not in MIDDLE of quote or comment or white-space of any type ... */
if (isSequenceReached(AS_OPEN_LINE_COMMENT))
{
isInLineComment = true;
if (shouldPadOperators)
appendSpacePad();
appendSequence(AS_OPEN_LINE_COMMENT);
goForward(1);
continue;
}
else if (isSequenceReached(AS_OPEN_COMMENT))
{
isInComment = true;
if (shouldPadOperators)
appendSpacePad();
appendSequence(AS_OPEN_COMMENT);
goForward(1);
continue;
}
else if (currentChar == '"' || currentChar == '\'')
{
isInQuote = true;
quoteChar = currentChar;
//// if (shouldPadOperators) // BUGFIX: these two lines removed. seem to be unneeded, and interfere with L"
//// appendSpacePad(); // BUFFIX: TODO make sure the removal of these lines doesn't reopen old bugs...
appendCurrentChar();
continue;
}
/* not in quote or comment or white-space of any type ... */
// check if in preprocessor
// ** isInPreprocessor will be automatically reset at the begining
// of a new line in getnextChar()
if (currentChar == '#')
isInPreprocessor = true;
if (isInPreprocessor)
{
appendCurrentChar();
continue;
}
/* not in preprocessor ... */
if (isImmediatelyPostComment)
{
isImmediatelyPostComment = false;
isCharImmediatelyPostComment = true;
}
if (isImmediatelyPostLineComment)
{
isImmediatelyPostLineComment = false;
isCharImmediatelyPostLineComment = true;
}
if (shouldBreakLineAfterComments)
{
shouldBreakLineAfterComments = false;
shouldReparseCurrentChar = true;
breakLine();
continue;
}
// reset isImmediatelyPostHeader information
if (isImmediatelyPostHeader)
{
isImmediatelyPostHeader = false;
isCharImmediatelyPostHeader = true;
// Make sure headers are broken from their succeeding blocks
// (e.g.
// if (isFoo) DoBar();
// should become
// if (isFoo)
// DoBar;
// )
// But treat else if() as a special case which should not be broken!
if (shouldBreakOneLineStatements)
{
// if may break 'else if()'s, ythen simply break the line
if (shouldBreakElseIfs)
isInLineBreak = true;
else
{
// make sure 'else if()'s are not broken.
bool isInElseIf = false;
const string *upcomingHeader;
upcomingHeader = findHeader(headers);
if (currentHeader == &AS_ELSE && upcomingHeader == &AS_IF)
isInElseIf = true;
if (!isInElseIf)
isInLineBreak = true; ////BUGFIX: SHOULD NOT BE breakLine() !!!
}
}
}
if (passedSemicolon)
{
passedSemicolon = false;
if (parenStack->back() == 0)
{
shouldReparseCurrentChar = true;
isInLineBreak = true;
continue;
}
}
if (passedColon)
{
passedColon = false;
if (parenStack->back() == 0)
{
shouldReparseCurrentChar = true;
isInLineBreak = true;
continue;
}
}
// Check if in template declaration, e.g. foo<bar> or foo<bar,fig>
// If so, set isInTemplate to true
//
if (!isInTemplate && currentChar == '<')
{
int templateDepth = 0;
const string *oper;
for (unsigned int i=charNum;
i< currentLine.length();
i += (oper ? oper->length() : 1) )
{
oper = ASBeautifier::findHeader(currentLine, i, operators);
if (oper == &AS_LS)
{
templateDepth++;
}
else if (oper == &AS_GR)
{
templateDepth--;
if (templateDepth == 0)
{
// this is a template!
//
isInTemplate = true;
break;
}
}
else if (oper == &AS_COMMA // comma, e.g. A<int, char>
|| oper == &AS_BIT_AND // reference, e.g. A<int&>
|| oper == &AS_MULT // pointer, e.g. A<int*>
|| oper == &AS_COLON_COLON) // ::, e.g. std::string
{
continue;
}
else if (!isLegalNameChar(currentLine[i]) && !isWhiteSpace(currentLine[i]))
{
// this is not a template -> leave...
//
isInTemplate = false;
break;
}
}
}
// handle parenthesies
//
if (currentChar == '(' || currentChar == '[' || (isInTemplate && currentChar == '<'))
{
parenStack->back()++;
}
else if (currentChar == ')' || currentChar == ']' || (isInTemplate && currentChar == '>'))
{
parenStack->back()--;
if (isInTemplate && parenStack->back() == 0)
{
isInTemplate = false;
isCharImmediatelyPostTemplate = true;
}
// check if this parenthesis closes a header, e.g. if (...), while (...)
//
if (isInHeader && parenStack->back() == 0)
{
isInHeader = false;
isImmediatelyPostHeader = true;
}
}
// handle brackets
//
BracketType bracketType = NULL_TYPE;
if (currentChar == '{')
{
bracketType = getBracketType();
foundPreDefinitionHeader = false;
foundPreCommandHeader = false;
bracketTypeStack->push_back(bracketType);
preBracketHeaderStack->push_back(currentHeader);
currentHeader = NULL;
isPreviousBracketBlockRelated = !IS_A(bracketType, ARRAY_TYPE);
}
else if (currentChar == '}')
{
// if a request has been made to append a post block empty line,
// but the block exists immediately before a closing bracket,
// then there is not need for the post block empty line.
//
isAppendPostBlockEmptyLineRequested = false;
if (!bracketTypeStack->empty())
{
bracketType = bracketTypeStack->back();
bracketTypeStack->pop_back();
isPreviousBracketBlockRelated = !IS_A(bracketType, ARRAY_TYPE);
}
if (!preBracketHeaderStack->empty())
{
currentHeader = preBracketHeaderStack->back();
preBracketHeaderStack->pop_back();
}
else
currentHeader = NULL;
}
if (!IS_A(bracketType, ARRAY_TYPE))
{
if (currentChar == '{')
{
parenStack->push_back(0);
}
else if (currentChar == '}')
{
if (!parenStack->empty())
{
parenStack->pop_back();
}
}
if (bracketFormatMode != NONE_MODE)
{
if (currentChar == '{')
{
if ( ( bracketFormatMode == ATTACH_MODE
|| bracketFormatMode == BDAC_MODE && bracketTypeStack->size()>=2
&& IS_A((*bracketTypeStack)[bracketTypeStack->size()-2], COMMAND_TYPE) /*&& isInLineBreak*/)
&& !isCharImmediatelyPostLineComment )
{
appendSpacePad();
if (!isCharImmediatelyPostComment // do not attach '{' to lines that end with /**/ comments.
&& previousCommandChar != '{'
&& previousCommandChar != '}'
&& previousCommandChar != ';') // '}' , ';' chars added for proper handling of '{' immediately after a '}' or ';'
appendCurrentChar(false);
else
appendCurrentChar(true);
continue;
}
else if (bracketFormatMode == BREAK_MODE
|| bracketFormatMode == BDAC_MODE && bracketTypeStack->size()>=2
&& IS_A((*bracketTypeStack)[bracketTypeStack->size()-2], DEFINITION_TYPE))
{
if ( shouldBreakOneLineBlocks || !IS_A(bracketType, SINGLE_LINE_TYPE) )
breakLine();
appendCurrentChar();
continue;
}
}
else if (currentChar == '}')
{
// bool origLineBreak = isInLineBreak;
// mark state of immediately after empty block
// this state will be used for locating brackets that appear immedately AFTER an empty block (e.g. '{} \n}').
if (previousCommandChar == '{')
isImmediatelyPostEmptyBlock = true;
if ( (!(previousCommandChar == '{' && isPreviousBracketBlockRelated) ) // this '{' does not close an empty block
&& (shouldBreakOneLineBlocks || !IS_A(bracketType, SINGLE_LINE_TYPE)) // astyle is allowed to break on line blocks
&& !isImmediatelyPostEmptyBlock) // this '}' does not immediately follow an empty block
{
breakLine();
appendCurrentChar();
}
else
{
// Content Patch ASFormatter.cpp.patch.bz2
// if (!isCharImmediatelyPostComment)
if (!isCharImmediatelyPostComment &&
!isCharImmediatelyPostLineComment)
isInLineBreak = false;
appendCurrentChar();
if (shouldBreakOneLineBlocks || !IS_A(bracketType, SINGLE_LINE_TYPE))
shouldBreakLineAfterComments = true;
}
if (shouldBreakBlocks)
{
isAppendPostBlockEmptyLineRequested =true;
}
continue;
}
}
}
if ( ( (previousCommandChar == '{'
&& isPreviousBracketBlockRelated)
|| (previousCommandChar == '}'
&& !isImmediatelyPostEmptyBlock // <--
&& isPreviousBracketBlockRelated
&& !isPreviousCharPostComment // <-- Fixes wrongly appended newlines after '}' immediately after comments... 10/9/1999
&& peekNextChar() != ' '))
&& (shouldBreakOneLineBlocks || !IS_A(bracketTypeStack->back(), SINGLE_LINE_TYPE)) )
{
isCharImmediatelyPostOpenBlock = (previousCommandChar == '{');
isCharImmediatelyPostCloseBlock = (previousCommandChar == '}');
previousCommandChar = ' ';
isInLineBreak = true; //<----
}
// reset block handling flags
isImmediatelyPostEmptyBlock = false;
// look for headers
if (!isInTemplate)
{
if ( (newHeader = findHeader(headers)) != NULL)
{
foundClosingHeader = false;
const string *previousHeader;
// recognize closing headers of do..while, if..else, try..catch..finally
if ( (newHeader == &AS_ELSE && currentHeader == &AS_IF)
|| (newHeader == &AS_WHILE && currentHeader == &AS_DO)
|| (newHeader == &AS_CATCH && currentHeader == &AS_TRY)
|| (newHeader == &AS_CATCH && currentHeader == &AS_CATCH)
|| (newHeader == &AS_FINALLY && currentHeader == &AS_TRY)
|| (newHeader == &AS_FINALLY && currentHeader == &AS_CATCH) )
foundClosingHeader = true;
previousHeader = currentHeader;
currentHeader = newHeader;
// If in ATTACH or LINUX bracket modes, attach closing headers (e.g. 'else', 'catch')
// to their preceding bracket,
// But do not perform the attachment if the shouldBreakClosingHeaderBrackets is set!
if (!shouldBreakClosingHeaderBrackets && foundClosingHeader && (bracketFormatMode == ATTACH_MODE || bracketFormatMode == BDAC_MODE) && previousNonWSChar == '}')
{
isInLineBreak = false;
appendSpacePad();
if (shouldBreakBlocks)
isAppendPostBlockEmptyLineRequested = false;
}
//Check if a template definition as been reached, e.g. template<class A>
if (newHeader == &AS_TEMPLATE)
{
isInTemplate = true;
}
// check if the found header is non-paren header
isNonParenHeader = ( find(nonParenHeaders.begin(), nonParenHeaders.end(),
newHeader) != nonParenHeaders.end() );
appendSequence(*currentHeader);
goForward(currentHeader->length() - 1);
// if padding is on, and a paren-header is found
// then add a space pad after it.
if (shouldPadOperators && !isNonParenHeader)
appendSpacePad();
// Signal that a header has been reached
// *** But treat a closing while() (as in do...while)
// as if it where NOT a header since a closing while()
// should never have a block after it!
if (!(foundClosingHeader && currentHeader == &AS_WHILE))
{
isInHeader = true;
if (isNonParenHeader)
{
isImmediatelyPostHeader = true;
isInHeader = false;
}
}
if (currentHeader == &AS_IF && previousHeader == &AS_ELSE)
isInLineBreak = false;
if (shouldBreakBlocks)
{
if (previousHeader == NULL
&& !foundClosingHeader
&& !isCharImmediatelyPostOpenBlock)
{
isPrependPostBlockEmptyLineRequested = true;
}
if (currentHeader == &AS_ELSE
|| currentHeader == &AS_CATCH
|| currentHeader == &AS_FINALLY
|| foundClosingHeader)
{
isPrependPostBlockEmptyLineRequested = false;
}
if (shouldBreakClosingHeaderBlocks
&& isCharImmediatelyPostCloseBlock)
{
isPrependPostBlockEmptyLineRequested = true;
}
}
continue;
}
else if ( (newHeader = findHeader(preDefinitionHeaders)) != NULL)
{
foundPreDefinitionHeader = true;
appendSequence(*newHeader);
goForward(newHeader->length() - 1);
if (shouldBreakBlocks)
isPrependPostBlockEmptyLineRequested = true;
continue;
}
else if ( (newHeader = findHeader(preCommandHeaders)) != NULL)
{
foundPreCommandHeader = true;
appendSequence(*newHeader);
goForward(newHeader->length() - 1);
continue;
}
}
if (previousNonWSChar == '}' || currentChar == ';')
{
if (shouldBreakOneLineStatements && currentChar == ';'
&& (shouldBreakOneLineBlocks || !IS_A(bracketTypeStack->back(), SINGLE_LINE_TYPE)))
{
passedSemicolon = true;
}
if (shouldBreakBlocks && currentHeader != NULL && parenStack->back() == 0)
{
isAppendPostBlockEmptyLineRequested = true;
}
if (currentChar != ';')
currentHeader = NULL; //DEVEL: is this ok?
foundQuestionMark = false;
foundPreDefinitionHeader = false;
foundPreCommandHeader = false;
isInPotentialCalculation = false;
}
if (currentChar == ':'
&& shouldBreakOneLineStatements
&& !foundQuestionMark // not in a ... ? ... : ... sequence
&& !foundPreDefinitionHeader // not in a definition block (e.g. class foo : public bar
&& previousCommandChar != ')' // not immediately after closing paren of a method header, e.g. ASFormatter::ASFormatter(...) : ASBeautifier(...)
&& previousChar != ':' // not part of '::'
&& peekNextChar() != ':') // not part of '::'
{
passedColon = true;
if (shouldBreakBlocks)
isPrependPostBlockEmptyLineRequested = true;
}
if (currentChar == '?')
foundQuestionMark = true;
if (shouldPadOperators)
{
if ((newHeader = findHeader(operators)) != NULL)
{
bool shouldPad = (newHeader != &AS_COLON_COLON
&& newHeader != &AS_PAREN_PAREN
&& newHeader != &AS_BLPAREN_BLPAREN
&& newHeader != &AS_PLUS_PLUS
&& newHeader != &AS_MINUS_MINUS
&& newHeader != &AS_NOT
&& newHeader != &AS_BIT_NOT
&& newHeader != &AS_ARROW
&& newHeader != &AS_OPERATOR
&& !(newHeader == &AS_MINUS && isInExponent())
&& !(newHeader == &AS_PLUS && isInExponent())
&& previousOperator != &AS_OPERATOR
&& !((newHeader == &AS_MULT || newHeader == &AS_BIT_AND)
&& isPointerOrReference())
&& !( (isInTemplate || isCharImmediatelyPostTemplate)
&& (newHeader == &AS_LS || newHeader == &AS_GR))
);
if (!isInPotentialCalculation)
if (find(assignmentOperators.begin(), assignmentOperators.end(), newHeader)
!= assignmentOperators.end())
isInPotentialCalculation = true;
// pad before operator
if (shouldPad
&& !(newHeader == &AS_COLON && !foundQuestionMark)
&& newHeader != &AS_SEMICOLON
&& newHeader != &AS_COMMA)
appendSpacePad();
appendSequence(*newHeader);
goForward(newHeader->length() - 1);
// since this block handles '()' and '[]',
// the parenStack must be updated here accordingly!
if (newHeader == &AS_PAREN_PAREN
|| newHeader == &AS_BLPAREN_BLPAREN)
parenStack->back()--;
currentChar = (*newHeader)[newHeader->length() - 1];
// pad after operator
// but do not pad after a '-' that is a urinary-minus.
if ( shouldPad && !(newHeader == &AS_MINUS && isUrinaryMinus()) )
appendSpacePad();
previousOperator = newHeader;
continue;
}
}
//BEGIN Content Patch patch1_ssvb_patch.tar.gz
if (currentChar == '(' || currentChar == '[' )
isInPotentialCalculation = true;
//END Content Patch patch1_ssvb_patch.tar.gz
if (shouldPadParenthesies)
{
if (currentChar == '(' || currentChar == '[' )
{
char peekedChar = peekNextChar();
isInPotentialCalculation = true;
appendCurrentChar();
if (!(currentChar == '(' && peekedChar == ')')
&& !(currentChar == '[' && peekedChar == ']'))
appendSpacePad();
continue;
}
else if (currentChar == ')' || currentChar == ']')
{
char peekedChar = peekNextChar();
if (!(previousChar == '(' && currentChar == ')')
&& !(previousChar == '[' && currentChar == ']'))
appendSpacePad();
appendCurrentChar();
if (peekedChar != ';' && peekedChar != ',' && peekedChar != '.'
&& !(currentChar == ']' && peekedChar == '['))
appendSpacePad();
continue;
}
}
appendCurrentChar();
}
// return a beautified (i.e. correctly indented) line.
string beautifiedLine;
int readyFormattedLineLength = trim(readyFormattedLine).length();
if (prependEmptyLine
&& readyFormattedLineLength > 0
&& previousReadyFormattedLineLength > 0)
{
isLineReady = true; // signal that a readyFormattedLine is still waiting
beautifiedLine = beautify("");
}
else
{
isLineReady = false;
beautifiedLine = beautify(readyFormattedLine);
}
prependEmptyLine = false;
previousReadyFormattedLineLength = readyFormattedLineLength;
return beautifiedLine;
}
/**
* check if there are any indented lines ready to be read by nextLine()
*
* @return are there any indented lines ready?
*/
bool ASFormatter::hasMoreLines() const
{
if (!isFormattingEnabled())
return ASBeautifier::hasMoreLines();
else
return !endOfCodeReached;
}
/**
* check if formatting options are enabled, in addition to indentation.
*
* @return are formatting options enabled?
*/
bool ASFormatter::isFormattingEnabled() const
{
return (bracketFormatMode != NONE_MODE
|| shouldPadOperators
|| shouldConvertTabs);
}
/**
* set the bracket formatting mode.
* options:
* astyle::NONE_MODE no formatting of brackets.
* astyle::ATTACH_MODE Java, K&R style bracket placement.
* astyle::BREAK_MODE ANSI C/C++ style bracket placement.
*
* @param mode the bracket formatting mode.
*/
void ASFormatter::setBracketFormatMode(BracketMode mode)
{
bracketFormatMode = mode;
}
/**
* set closing header bracket breaking mode
* options:
* true brackets just before closing headers (e.g. 'else', 'catch')
* will be broken, even if standard brackets are attached.
* false closing header brackets will be treated as standard brackets.
*
* @param mode the closing header bracket breaking mode.
*/
void ASFormatter::setBreakClosingHeaderBracketsMode(bool state)
{
shouldBreakClosingHeaderBrackets = state;
}
/**
* set 'else if()' breaking mode
* options:
* true 'else' headers will be broken from their succeeding 'if' headers.
* false 'else' headers will be attached to their succeeding 'if' headers.
*
* @param mode the 'else if()' breaking mode.
*/
void ASFormatter::setBreakElseIfsMode(bool state)
{
shouldBreakElseIfs = state;
}
/**
* set operator padding mode.
* options:
* true statement operators will be padded with spaces around them.
* false statement operators will not be padded.
*
* @param mode the padding mode.
*/
void ASFormatter::setOperatorPaddingMode(bool state)
{
shouldPadOperators = state;
}
/**
* set parentheies padding mode.
* options:
* true statement parenthesies will be padded with spaces around them.
* false statement parenthesies will not be padded.
*
* @param mode the padding mode.
*/
void ASFormatter::setParenthesisPaddingMode(bool state)
{
shouldPadParenthesies = state;
}
/**
* set option to break/not break one-line blocks
*
* @param state true = break, false = don't break.
*/
void ASFormatter::setBreakOneLineBlocksMode(bool state)
{
shouldBreakOneLineBlocks = state;
}
/**
* set option to break/not break lines consisting of multiple statements.
*
* @param state true = break, false = don't break.
*/
void ASFormatter::setSingleStatementsMode(bool state)
{
shouldBreakOneLineStatements = state;
}
/**
* set option to convert tabs to spaces.
*
* @param state true = convert, false = don't convert.
*/
void ASFormatter::setTabSpaceConversionMode(bool state)
{
shouldConvertTabs = state;
}
/**
* set option to break unrelated blocks of code with empty lines.
*
* @param state true = convert, false = don't convert.
*/
void ASFormatter::setBreakBlocksMode(bool state)
{
shouldBreakBlocks = state;
}
/**
* set option to break closing header blocks of code (such as 'else', 'catch', ...) with empty lines.
*
* @param state true = convert, false = don't convert.
*/
void ASFormatter::setBreakClosingHeaderBlocksMode(bool state)
{
shouldBreakClosingHeaderBlocks = state;
}
/**
* check if a specific sequence exists in the current placement of the current line
*
* @return whether sequence has been reached.
* @param sequence the sequence to be checked
*/
bool ASFormatter::isSequenceReached(const string &sequence) const
{
return currentLine.COMPARE(charNum, sequence.length(), sequence) == 0;
}
/**
* jump over several characters.
*
* @param i the number of characters to jump over.
*/
void ASFormatter::goForward(int i)
{
while (--i >= 0)
getNextChar();
}
/**
* peek at the next unread character.
*
* @return the next unread character.
*/
char ASFormatter::peekNextChar() const
{
int peekNum = charNum + 1;
int len = currentLine.length();
char ch = ' ';
while (peekNum < len)
{
ch = currentLine[peekNum++];
if (!isWhiteSpace(ch))
return ch;
}
if (shouldConvertTabs && ch == '\t')
ch = ' ';
return ch;
}
/**
* check if current placement is before a comment or line-comment
*
* @return is before a comment or line-comment.
*/
bool ASFormatter::isBeforeComment() const
{
int peekNum = charNum + 1;
int len = currentLine.length();
// char ch = ' ';
bool foundComment = false;
for (peekNum = charNum + 1;
peekNum < len && isWhiteSpace(currentLine[peekNum]);
++peekNum)
;
if (peekNum < len)
foundComment = ( currentLine.COMPARE(peekNum, 2, AS_OPEN_COMMENT) == 0
|| currentLine.COMPARE(peekNum, 2, AS_OPEN_LINE_COMMENT) == 0 );
return foundComment;
}
/**
* get the next character, increasing the current placement in the process.
* the new character is inserted into the variable currentChar.
*
* @return whether succeded to recieve the new character.
*/
bool ASFormatter::getNextChar()
{
isInLineBreak = false;
bool isAfterFormattedWhiteSpace = false;
if (shouldPadOperators && !isInComment && !isInLineComment
&& !isInQuote && !doesLineStartComment && !isInPreprocessor
&& !isBeforeComment())
{
//BEGIN Content Patch patch1_ssvb_patch.tar.gz
char prevchar = ' ';
char nextchar = peekNextChar();
int len = formattedLine.length();
// if (len > 0 && isWhiteSpace(formattedLine[len-1]))
if (len > 0) prevchar = formattedLine[len-1];
if (isWhiteSpace(prevchar) || prevchar == '(' || prevchar == '[' ||
nextchar == ')' || nextchar == ']')
{
isAfterFormattedWhiteSpace = true;
}
//END Content Patch patch1_ssvb_patch.tar.gz
}
previousChar = currentChar;
if (!isWhiteSpace(currentChar))
{
previousNonWSChar = currentChar;
if (!isInComment && !isInLineComment && !isInQuote
&& !isSequenceReached(AS_OPEN_COMMENT)
&& !isSequenceReached(AS_OPEN_LINE_COMMENT) )
previousCommandChar = previousNonWSChar;
}
unsigned int currentLineLength = currentLine.length();
if (charNum+1 < currentLineLength
&& (!isWhiteSpace(peekNextChar()) || isInComment || isInLineComment))
{
currentChar = currentLine[++charNum];
if (isAfterFormattedWhiteSpace)
while (isWhiteSpace(currentChar) && charNum+1 < currentLineLength)
currentChar = currentLine[++charNum];
if (shouldConvertTabs && currentChar == '\t')
currentChar = ' ';
return true;
}
// BEGIN Content patch ASFormatter450670.patch.bz2
else if (isInLineComment && (charNum+1 == currentLineLength))
{
// fix BUG #450670
currentChar = ' ';
return true;
}
// END Content patch ASFormatter450670.patch.bz2
else
{
if (sourceIterator->hasMoreLines())
{
currentLine = sourceIterator->nextLine();
if (currentLine.length() == 0)
{
/*think*/ currentLine = string(" ");
}
// unless reading in the first line of the file,
// break a new line.
if (!isVirgin)
isInLineBreak = true;
else
isVirgin = false;
if (isInLineComment)
isImmediatelyPostLineComment = true;
isInLineComment = false;
trimNewLine();
currentChar = currentLine[charNum];
// check if is in preprocessor right after the line break and line trimming
if (previousNonWSChar != '\\')
isInPreprocessor = false;
if (shouldConvertTabs && currentChar == '\t')
currentChar = ' ';
return true;
}
else
{
endOfCodeReached = true;
return false;
}
}
}
/**
* jump over the leading white space in the current line,
* IF the line does not begin a comment or is in a preprocessor definition.
*/
void ASFormatter::trimNewLine()
{
unsigned int len = currentLine.length();
charNum = 0;
if (isInComment || isInPreprocessor)
return;
while (isWhiteSpace(currentLine[charNum]) && charNum+1 < len)
++charNum;
doesLineStartComment = false;
if (isSequenceReached(string("/*")))
{
charNum = 0;
doesLineStartComment = true;
}
}
/**
* append a character to the current formatted line.
* Unless disabled (via canBreakLine == false), first check if a
* line-break has been registered, and if so break the
* formatted line, and only then append the character into
* the next formatted line.
*
* @param ch the character to append.
* @param canBreakLine if true, a registered line-break
*/
void ASFormatter::appendChar(char ch, bool canBreakLine)
{
if (canBreakLine && isInLineBreak)
breakLine();
formattedLine.append(1, ch);
}
/**
* append the CURRENT character (curentChar)to the current
* formatted line. Unless disabled (via canBreakLine == false),
* first check if a line-break has been registered, and if so
* break the formatted line, and only then append the character
* into the next formatted line.
*
* @param canBreakLine if true, a registered line-break
*/
void ASFormatter::appendCurrentChar(bool canBreakLine)
{
appendChar(currentChar, canBreakLine);
}
/**
* append a string sequence to the current formatted line.
* Unless disabled (via canBreakLine == false), first check if a
* line-break has been registered, and if so break the
* formatted line, and only then append the sequence into
* the next formatted line.
*
* @param sequence the sequence to append.
* @param canBreakLine if true, a registered line-break
*/
void ASFormatter::appendSequence(const string &sequence, bool canBreakLine)
{
if (canBreakLine && isInLineBreak)
breakLine();
formattedLine.append(sequence);
}
/**
* append a space to the current formattedline, UNLESS the
* last character is already a white-space character.
*/
void ASFormatter::appendSpacePad()
{
int len = formattedLine.length();
if (len == 0 || !isWhiteSpace(formattedLine[len-1]))
formattedLine.append(1, ' ');
}
/**
* register a line break for the formatted line.
*/
void ASFormatter::breakLine()
{
isLineReady = true;
isInLineBreak = false;
// queue an empty line prepend request if one exists
prependEmptyLine = isPrependPostBlockEmptyLineRequested;
readyFormattedLine = formattedLine;
if (isAppendPostBlockEmptyLineRequested)
{
isAppendPostBlockEmptyLineRequested = false;
isPrependPostBlockEmptyLineRequested = true;
}
else
{
isPrependPostBlockEmptyLineRequested = false;
}
formattedLine = "";
}
/**
* check if the currently reached open-bracket (i.e. '{')
* opens a:
* - a definition type block (such as a class or namespace),
* - a command block (such as a method block)
* - a static array
* this method takes for granted that the current character
* is an opening bracket.
*
* @return the type of the opened block.
*/
BracketType ASFormatter::getBracketType() const
{
BracketType returnVal;
if (foundPreDefinitionHeader)
returnVal = DEFINITION_TYPE;
else
{
bool isCommandType;
isCommandType = ( foundPreCommandHeader
|| ( currentHeader != NULL && isNonParenHeader )
|| ( previousCommandChar == ')' )
|| ( previousCommandChar == ':' && !foundQuestionMark )
|| ( previousCommandChar == ';' )
|| ( ( previousCommandChar == '{' || previousCommandChar == '}')
&& isPreviousBracketBlockRelated ) );
returnVal = (isCommandType ? COMMAND_TYPE : ARRAY_TYPE);
}
if (isOneLineBlockReached())
returnVal = (BracketType) (returnVal | SINGLE_LINE_TYPE);
return returnVal;
}
/**
* check if the currently reached '*' or '&' character is
* a pointer-or-reference symbol, or another operator.
* this method takes for granted that the current character
* is either a '*' or '&'.
*
* @return whether current character is a reference-or-pointer
*/
bool ASFormatter::isPointerOrReference() const
{
bool isPR;
isPR = ( !isInPotentialCalculation
|| IS_A(bracketTypeStack->back(), DEFINITION_TYPE)
|| (!isLegalNameChar(previousNonWSChar)
&& previousNonWSChar != ')'
&& previousNonWSChar != ']')
);
if (!isPR)
{
char nextChar = peekNextChar();
isPR |= (!isWhiteSpace(nextChar)
&& nextChar != '-'
&& nextChar != '('
&& nextChar != '['
&& !isLegalNameChar(nextChar));
}
return isPR;
}
/**
* check if the currently reached '-' character is
* a urinary minus
* this method takes for granted that the current character
* is a '-'.
*
* @return whether the current '-' is a urinary minus.
*/
bool ASFormatter::isUrinaryMinus() const
{
return ( (previousOperator == &AS_RETURN || !isalnum(previousCommandChar))
&& previousCommandChar != '.'
&& previousCommandChar != ')'
&& previousCommandChar != ']' );
}
/**
* check if the currently reached '-' or '+' character is
* part of an exponent, i.e. 0.2E-5.
* this method takes for granted that the current character
* is a '-' or '+'.
*
* @return whether the current '-' is in an exponent.
*/
bool ASFormatter::isInExponent() const
{
int formattedLineLength = formattedLine.length();
if (formattedLineLength >= 2)
{
char prevPrevFormattedChar = formattedLine[formattedLineLength - 2];
char prevFormattedChar = formattedLine[formattedLineLength - 1];
return ( (prevFormattedChar == 'e' || prevFormattedChar == 'E')
&& (prevPrevFormattedChar == '.' || isdigit(prevPrevFormattedChar)) );
}
else
return false;
}
/**
* check if a one-line bracket has been reached,
* i.e. if the currently reached '{' character is closed
* with a complimentry '}' elsewhere on the current line,
*.
* @return has a one-line bracket been reached?
*/
bool ASFormatter::isOneLineBlockReached() const
{
bool isInComment = false;
bool isInQuote = false;
int bracketCount = 1;
int currentLineLength = currentLine.length();
int i = 0;
char ch = ' ';
char quoteChar = ' ';
for (i = charNum + 1; i < currentLineLength; ++i)
{
ch = currentLine[i];
if (isInComment)
{
if (currentLine.COMPARE(i, 2, "*/") == 0)
{
isInComment = false;
++i;
}
continue;
}
if (ch == '\\')
{
++i;
continue;
}
if (isInQuote)
{
if (ch == quoteChar)
isInQuote = false;
continue;
}
if (ch == '"' || ch == '\'')
{
isInQuote = true;
quoteChar = ch;
continue;
}
if (currentLine.COMPARE(i, 2, "//") == 0)
break;
if (currentLine.COMPARE(i, 2, "/*") == 0)
{
isInComment = true;
++i;
continue;
}
if (ch == '{')
++bracketCount;
else if (ch == '}')
--bracketCount;
if(bracketCount == 0)
return true;
}
return false;
}
/**
* check if one of a set of headers has been reached in the
* current position of the current line.
*
* @return a pointer to the found header. Or a NULL if no header has been reached.
* @param headers a vector of headers
* @param checkBoundry
*/
const string *ASFormatter::findHeader(const vector<const string*> &headers, bool checkBoundry)
{
return ASBeautifier::findHeader(currentLine, charNum, headers, checkBoundry);
}
#ifdef USES_NAMESPACE
}
#endif